avatar

目录
value iteration代码解释

Search 算法20题代码解释

好的,我们来用中文详细解释一下第20题的解法。

问题分析

第20题要求我们为一个在网格中行驶的汽车找到一条最优路径。和之前的问题不同,这道题的状态不仅包括汽车的位置(行和列),还包括它的朝向(上、下、左、右)。此外,汽车的移动成本也变得更复杂:直行、左转和右转的成本是不同的。

核心思想:动态规划 (Value Iteration)

解决这类问题的经典方法是动态规划,具体来说是价值迭代 (Value Iteration) 算法。这个思想和第18题的 compute_value 函数非常相似,但我们需要将它扩展到一个三维的状态空间。

  1. 状态空间 (State Space)

    • 之前我们的状态只需要 (row, col)
    • 现在,因为朝向会影响下一步的移动和成本,所以我们的状态必须是 (row, col, direction)。我们有4个朝向,所以状态空间的大小是 行数 x 列数 x 4
  2. 价值函数 (Value Function)

    • 我们需要一个三维的 value 表,value[d][r][c] 记录的是:当汽车在 (r, c) 位置并且朝向为 d 时,到达终点所需的最小成本
    • 我们将这个表初始化为一个非常大的数(例如999),表示初始时我们不知道到达终点的成本。
  3. 策略函数 (Policy Function)

    • 同样,我们需要一个三维的 policy 表,policy[d][r][c] 记录的是:当汽车在 (r, c) 位置并且朝向为 d 时,为了以最小成本到达终点,它下一步应该执行什么动作(右转’R’,直行’#’,或左转’L’)。

算法步骤

算法分为两个主要阶段:

第一阶段:计算所有状态的价值 (Value Iteration)

这个阶段的目标是填满 valuepolicy 这两个三维表。我们使用一个循环,不断地更新每个状态的价值,直到价值不再变化为止。这个过程就像水波从终点反向传播一样。

  1. 初始化

    • 将所有状态的 value 设为 999。
    • 将终点 goalvalue 设为 0,因为在终点时,到达终点的成本就是0。它的 policy 设为 *
  2. 迭代更新

    • 我们用一个 while change 循环,只要在上一轮迭代中有任何 value 值被更新,就继续循环。
    • 在循环内部,我们遍历每一个可能的状态 (r, c, d)
    • 对于一个非终点的状态 (r, c, d),我们尝试三种可能的动作(右转、直行、左转):

      • 对于每一种动作,我们计算出执行该动作后的新朝向 d2新位置 (r2, c2)
      • 然后,我们计算通过这个动作到达终点的总成本v2 = 动作成本 + value[d2][r2][c2]。这个公式的含义是:从 (r, c, d) 出发,执行这个动作,然后从新的状态 (r2, c2, d2) 出发到达终点的最小成本。
      • 我们比较这个 v2 和当前记录的 value[d][r][c]。如果 v2 更小,说明我们找到了一个更好的路径。我们就更新 value[d][r][c] = v2,并把对应的动作记录到 policy[d][r][c] 中。
    • 这个过程会一直持续,直到网络中所有节点的 value 都收敛到最优值。

第二阶段:回溯路径 (Traceback)

当我们完成了第一阶段,policy 表里就存储了从任何状态出发的最佳决策。现在,我们只需要从给定的 init 初始状态 (r, c, d) 开始,按照 policy 表的指引一步一步走,就可以得到最优路径。

  1. 从初始状态开始:获取 initr, c, d
  2. 循环移动
    • policy2D 这个二维网格的 (r, c) 位置,记录下当前状态 (r, c, d) 对应的最佳动作 policy[d][r][c]
    • 根据这个动作,计算出汽车的新朝向新位置
    • 更新 r, c, d 为新的值。
    • 重复这个过程,直到汽车到达 goal 位置。
  3. 标记终点:最后,在 policy2D 的终点位置标记一个 *

最终返回的 policy2D 就是我们要求解的、从特定初始状态出发的最优路径图。

代码解析

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
def optimum_policy2D(grid,init,goal,cost):
# value[d][r][c]: 从朝向为d, 位置(r,c)的状态到终点的最小成本
value = [[[999 for col in range(len(grid[0]))] for row in range(len(grid))] for i in range(4)]

# policy[d][r][c]: 从朝向为d, 位置(r,c)的状态出发的最佳动作
policy = [[[' ' for col in range(len(grid[0]))] for row in range(len(grid))] for i in range(4)]

# policy2D: 最终从init状态回溯出的路径
policy2D = [[' ' for col in range(len(grid[0]))] for row in range(len(grid))]

# --- 第一阶段:价值迭代 ---
change = True
while change:
change = False
# 遍历所有状态 (r, c, d)
for r in range(len(grid)):
for c in range(len(grid[0])):
for d in range(len(forward)):
# 如果是终点
if r == goal[0] and c == goal[1]:
if value[d][r][c] > 0:
value[d][r][c] = 0
policy[d][r][c] = '*'
change = True
# 如果是可通行网格
elif grid[r][c] == 0:
# 遍历所有动作 (右转, 直行, 左转)
for i in range(len(action)):
d2 = (d + action[i]) % 4 # 新朝向
r2 = r + forward[d2][0] # 新行
c2 = c + forward[d2][1] # 新列

# 如果移动后的位置合法
if r2 >= 0 and r2 < len(grid) and c2 >= 0 and c2 < len(grid[0]) and grid[r2][c2] == 0:
# 计算新成本 = 动作成本 + 后续成本
v2 = value[d2][r2][c2] + cost[i]

# 如果找到了更优的路径
if v2 < value[d][r][c]:
value[d][r][c] = v2
policy[d][r][c] = action_name[i]
change = True

# --- 第二阶段:回溯路径 ---
r, c, d = init

# 只要没到终点就一直走
while r != goal[0] or c != goal[1]:
# 在2D路径图上记录当前位置的最佳动作
policy2D[r][c] = policy[d][r][c]
action_char = policy[d][r][c]

if action_char == ' ': # 如果没有路了
break

# 根据动作更新朝向和位置
turn = action[action_name.index(action_char)]
d = (d + turn) % 4
r += forward[d][0]
c += forward[d][1]

# 标记终点
policy2D[goal[0]][goal[1]] = '*'

return policy2D

评论